package mygame;

import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable;
import gameobject.item.Item;
import gameobject.item.RequiredItemHolder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Inventory implements Savable {
    protected Map<Class<?>, Item> itemMap = new HashMap<Class<?>, Item>();

    public List<Item> getItems() {
	return new ArrayList<Item>(itemMap.values());
    }

    public void addItem(Item item) {
	if(itemMap.containsKey(item.getClass()))
	    itemMap.get(item.getClass()).changeQuantity(item.getQuantity());
	else
	    itemMap.put(item.getClass(), item);
    }

    public void addItems(List<Item> items) {
	for(Item item : items)
	    addItem(item);
    }

    /**
     * Removes and returns as many of the given item (with quantity) as possible. If not in the map, returns null.
     */
    public Item popItemWithQuantity(Item itemToPop) {
	if(itemMap.containsKey(itemToPop.getClass())) {
            Item itemInMap = itemMap.get(itemToPop.getClass());
            if(itemInMap.getQuantity() > itemToPop.getQuantity()) {
                itemInMap.changeQuantity(-itemToPop.getQuantity());
                return itemToPop.clone();
            } else {
                Item savedItem = itemInMap.clone();
                itemMap.remove(itemToPop.getClass());
                return savedItem;
            }
	} else {
	    return null;
	}
    }

    public List<Item> popAllItems() {
	List<Item> savedItems = new ArrayList<Item>(itemMap.values());
	itemMap.clear();
	return savedItems;
    }
    
    public boolean containsItemWithoutQuantity(Item item) {
        return itemMap.containsKey(item.getClass());
    }

    public boolean containsItemWithQuantity(Item item) {
	if(itemMap.containsKey(item.getClass()) && itemMap.get(item.getClass()).getQuantity() >= item.getQuantity())
	    return true;
	else
	    return false;
    }

    public boolean containsRequiredItemsWithQuantities(EnumMap<RequiredItemHolder, List<Item>> requiredItems, RequiredItemHolder requiredItemHolder) {
	for(Item requiredItem : requiredItems.get(requiredItemHolder)) {
	    if(!containsItemWithQuantity(requiredItem))
		return false;
	}
	return true;
    }
    
    /**
     * Attempts to transfer required items from the given inventory to this one.
     * Returns true if anything was transferred, false if nothing was transferred.
     */
    public boolean transferRequiredItems(Inventory transferFrom, EnumMap<RequiredItemHolder, List<Item>> requiredItems, RequiredItemHolder requiredItemHolder) {
        boolean somethingWasTransferred = false;
        for(Item requiredItem : requiredItems.get(requiredItemHolder)) {
            if(transferFrom.containsItemWithoutQuantity(requiredItem)) {
                addItem(transferFrom.popItemWithQuantity(requiredItem));
                somethingWasTransferred = true;
            }
        }
        return somethingWasTransferred;
    }

    @Override
    public void write(JmeExporter ex) throws IOException {
	OutputCapsule capsule = ex.getCapsule(this);
	capsule.writeSavableArrayList(new ArrayList<Item>(itemMap.values()), "items", null);
    }

    @Override
    @SuppressWarnings("unchecked")
    public void read(JmeImporter im) throws IOException {
	InputCapsule capsule = im.getCapsule(this);
	ArrayList<Item> loadedItems = capsule.readSavableArrayList("items", null);
	addItems(loadedItems);
    }

    @Override
    public String toString() {
	return getItems().toString();
    }
}
